{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 上节问题回顾"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "任务队列阻塞问题\n",
    "\n",
    "- 问题背景: 当线程池所有线程都在执行任务且任务队列已满时，用户调用`submitTask`接口会被无限期阻塞\n",
    "- 关键矛盾:\n",
    "  - 用户线程不应因线程池内部资源不足而被长时间阻塞\n",
    "  - 任务队列堆积可能导致内存溢出等严重问题"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "解决方案设计\n",
    "\n",
    "- 超时机制:\n",
    "  - 使用条件变量的带超时等待功能：`notFull_.wait(lock, [&]()->bool {...})`\n",
    "  - 最长阻塞时间设置为1秒（关键数字）\n",
    "- 降级处理:\n",
    "  - 超时后判定任务提交失败\n",
    "  - 类比分布式系统中的服务降级策略\n",
    "  - 防止任务无限堆积导致内存崩溃"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "实现要点\n",
    "\n",
    "- 条件变量使用:\n",
    "  - `notFull_`条件变量：监控队列是否已满\n",
    "  - `notEmpty_`条件变量：监控队列是否为空\n",
    "- 线程安全:\n",
    "  - 使用`std::unique_lock<std::mutex>`保证操作原子性\n",
    "  - 任务入队后立即通过`notify_all()`唤醒工作线程\n",
    "- 参数配置:\n",
    "  - 通过`setTaskQueMaxThreshHold`方法动态调整队列容量\n",
    "  - 默认阈值设为1024（关键数字）"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 任务提交失败处理"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "条件变量的阻塞方法\n",
    "- 三种阻塞方式: C++11提供了`wait`、`wait_for`和`wait_until`三种条件变量阻塞方法\n",
    "- 应用场景: 根据不同的时间控制需求选择相应方法"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "wait方法介绍 \n",
    "\n",
    "- 特点: 与时间无关的阻塞方式\n",
    "- 工作方式:\n",
    "  - 无条件等待: 会一直阻塞直到条件满足\n",
    "  - 手动检查: 需要在外层添加循环判断条件\n",
    "- 比喻说明: 类似\"我等你回心转意，你不回心转意我就一直等\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`wait_for`方法介绍\n",
    "\n",
    "- 时间参数: 接受一个持续时间参数\n",
    "- 工作方式:\n",
    "  - 限时等待: 最多等待指定时长\n",
    "  - 提前唤醒: 条件满足时立即返回\n",
    "- 比喻说明: 类似\"我最多等你三天，三天后不管结果如何都会离开\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`wait_until`方法介绍\n",
    "\n",
    "- 时间参数: 接受一个绝对时间点参数\n",
    "- 工作方式:\n",
    "  - 截止等待: 等待到指定时间点\n",
    "  - 时间基准: 使用具体的时间节点而非持续时间\n",
    "- 比喻说明: 类似\"我等你到下周一，再不回头就放弃\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`wait_for`方法的应用\n",
    "\n",
    "- 参数说明:\n",
    "  - 锁对象: 第一个参数为互斥锁\n",
    "  - 时间单位: 使用chrono库封装的时间单位(秒/毫秒/微秒/纳秒)\n",
    "  - 谓词函数: 第三个参数为条件判断函数\n",
    "- 实现细节:\n",
    "  - 时间设置: 使用`std::chrono::seconds(1)`表示1秒超时\n",
    "  - 条件判断: 检查任务队列大小是否小于阈值"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`wait_for`返回值解释"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 返回值类型: 布尔值\n",
    "- 返回值含义:\n",
    "  - `true`: 条件在超时前满足\n",
    "  - `false`: 超时后条件仍未满足\n",
    "- 错误处理:\n",
    "  - 日志记录: 当返回`false`时记录\"task queue is full, submit task fail\"\n",
    "  - 流程控制: 直接返回表示任务提交失败\n",
    "- 设计考虑:\n",
    "  - 用户体验: 避免用户长时间等待\n",
    "  - 系统健壮性: 防止因队列满导致系统阻塞"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 线程函数实现"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "线程函数的执行\n",
    "\n",
    "- 核心功能：线程池中所有线程共同执行的函数，负责从任务队列消费任务\n",
    "- 执行机制：若初始4个线程，则4个线程同时执行该函数\n",
    "- 任务处理：通过循环不断从任务队列中取出任务进行处理，而非单次处理"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "线程函数的循环执行\n",
    "\n",
    "- 持续运行：线程需要保持运行状态持续处理任务，不能处理完单个任务就结束\n",
    "- 控制机制：后续会添加线程池运行状态变量控制线程函数终止\n",
    "- 实现方式：使用无限循环结构`for(;;)`保持线程持续运行"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "线程函数的等待条件\n",
    "\n",
    "- 同步机制：必须先获取互斥锁才能访问任务队列\n",
    "- 等待条件：当任务队列为空时，线程需要等待`notEmpty`条件变量\n",
    "- 阻塞特性：不同于定时等待，线程会持续阻塞直到有任务到来\n",
    "- 条件判断：使用`wait(lock, [&]()->bool{return taskQue_.size()>0;})`确保队列非空"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "线程函数的取任务操作 \n",
    "\n",
    "- 任务提取：使用`auto task = taskQue_.front()`获取队列头部任务\n",
    "- 队列维护：必须调用`taskQue_.pop()`从队列中移除已取出的任务\n",
    "- 计数更新：每次取任务后需要执行`taskSize_--`更新任务计数器"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "线程函数的任务执行\n",
    "\n",
    "- 多态调用：通过基类指针`task->run()`调用派生类的具体实现\n",
    "- 设计模式：采用继承+多态的设计模式，为不同任务类型提供统一接口\n",
    "- 执行时机：获取任务后立即在当前线程执行，无需额外调度\n",
    "- 资源管理：任务执行完毕后自动释放资源，无需手动管理内存"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 代码检查"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "线程池任务执行逻辑\n",
    "\n",
    "- 基本流程：线程从任务队列获取任务并执行的完整流程\n",
    "  - 获取锁保证线程安全\n",
    "  - 等待条件变量`notEmpty_`满足（任务队列非空）\n",
    "  - 从队列取出任务并减少任务计数\n",
    "  - 执行任务\n",
    "- 不合理设计：原实现将任务执行包含在锁的作用域内，导致其他线程无法并发获取任务"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "锁的管理与任务执行\n",
    "\n",
    "- 锁的正确使用：\n",
    "  - 作用范围：锁应仅保护共享资源（任务队列）的访问\n",
    "  - 释放时机：任务取出后应立即释放锁，不应包含任务执行过程\n",
    "- 常见错误：线程长时间持有锁会导致其他线程阻塞，形成\"单线程工作\"假象"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "锁的作用域与任务执行 \n",
    "\n",
    "- 改进方案：\n",
    "  - 使用局部作用域限制锁的范围（通过`{}`创建代码块）\n",
    "  - 任务对象应在锁释放后执行\n",
    "- 实现细节：\n",
    "  - `std::unique_lock`在作用域结束时自动释放\n",
    "  - 任务执行与队列操作分离，提高并发性"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`task`对象的定义与赋值\n",
    "\n",
    "- 智能指针管理：\n",
    "  - 使用`std::shared_ptr<Task>`存储任务对象\n",
    "  - 在循环外定义`task`变量（默认构造为空指针）\n",
    "  - 在锁保护区内进行赋值操作\n",
    "- 异常处理：\n",
    "  - 执行前检查`task`非空\n",
    "  - 防止空指针导致的程序崩溃"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "合理的线程池实现\n",
    "\n",
    "- 最终实现要点：\n",
    "  - 定义任务指针变量\n",
    "  - 加锁并等待条件满足\n",
    "  - 取出任务后立即释放锁\n",
    "  - 在锁外执行任务\n",
    "  - 添加空指针检查\n",
    "- 性能优势：允许线程并行执行任务，提高资源利用率"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "多线程程序中的锁释放问题\n",
    "\n",
    "- 调试技巧：\n",
    "  - 现象诊断：当发现始终只有一个线程工作时，应检查锁的持有时间\n",
    "  - 最佳实践：锁应仅保护必要的临界区代码\n",
    "- 设计原则：\n",
    "  - 锁粒度尽可能小\n",
    "  - 避免在锁内执行耗时操作\n",
    "  - 使用RAII管理锁资源"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 测试线程池"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "线程池项目概述\n",
    "\n",
    "- 线程启动机制：通过循环启动所有线程，调用`threads_[i]->start()`方法执行线程函数\n",
    "- 线程函数定义：`ThreadPool::threadFunc()`负责从任务队列消费任务"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "线程函数与任务消费\n",
    "\n",
    "消费流程：\n",
    "\n",
    "- 使用`std::unique_lock<std::mutex>`保护任务队列\n",
    "- 通过`notEmpty_.wait()`等待队列非空条件\n",
    "- 获取任务后立即释放锁"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "务执行与通知机制\n",
    "\n",
    "- 双重通知机制：\n",
    "  - 消费后通知：取出任务后调用`notFull_.notify_all()`通知生产者可以继续提交任务\n",
    "  - 剩余任务通知：如果队列仍有任务(`taskQue_.size() > 0`)，调用`notEmpty_.notify_all()`唤醒其他消费者线程\n",
    "- 类比说明：如同第一个吃螃蟹的人发现还有剩余时招呼其他人来吃，避免线程空等"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "线程间通信与条件变量\n",
    "\n",
    "- 条件变量配对原则：\n",
    "  - 每个`wait`必须有对应的`notify`，类似`new/delete`必须成对出现\n",
    "  - 使用两个条件变量(`notEmpty_`和`notFull_)`实现更精细的线程通信\n",
    "- 错误处理：警告提示有符号/无符号类型不匹配，需进行强制类型转换"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "任务队列与锁管理\n",
    "\n",
    "- 队列操作流程：\n",
    "  - 获取任务：`task = taskQue_.front()`\n",
    "  - 移除任务：`taskQue_.pop()`\n",
    "  - 更新计数：`taskSize_--`\n",
    "- 锁释放时机：任务取出后应立即释放锁，避免长时间持有影响性能"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "提交任务与队列状态检查\n",
    "\n",
    "- 提交限制：\n",
    "  - 使用`wait_for`设置1秒超时，防止长时间阻塞\n",
    "  - 队列满时输出错误信息\"task queue is full, submit task fail.\"\n",
    "- 成功处理：\n",
    "  - 任务入队：`taskQue_.emplace(sp)`\n",
    "  - 计数增加：`taskSize_++`\n",
    "  - 通知消费者：n`otEmpty_.notify_all()`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "线程池启动与线程创建 \n",
    "\n",
    "初始化过程：\n",
    "\n",
    "- 记录初始线程数：`initThreadSize_ = initThreadSize`\n",
    "- 创建线程对象：使用`std::make_unique<Thread>`绑定线程函数\n",
    "- 线程对象管理：存入`threads_`向量容器"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "线程池构造与析构\n",
    "\n",
    "- 初始化列表：\n",
    "  - `initThreadSize_(0)`：初始线程数\n",
    "  - `taskSize_(0)`：任务计数\n",
    "  - `taskQueMaxThreshHold_(TASK_MAX_THRESHHOLD)`：队列最大阈值(1024)\n",
    "  - `poolMode_(PoolMode::MODE_FIXED)`：默认固定模式\n",
    "- 模式设置：通过`setMode()`方法可动态修改线程池工作模式"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "C++17",
   "language": "C++17",
   "name": "xcpp17"
  },
  "language_info": {
   "name": "C++17"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
